/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.muni.fi.diplomka.servicelayer.gamelogic.managerimpl;

import cz.fi.muni.diplomka.common.enumeration.BuildingType;
import cz.fi.muni.diplomka.common.enumeration.ResourceType;
import static cz.fi.muni.diplomka.common.enumeration.ResourceType.Food;
import static cz.fi.muni.diplomka.common.enumeration.ResourceType.Gold;
import static cz.fi.muni.diplomka.common.enumeration.ResourceType.Stone;
import cz.muni.fi.diplomka.datalayer.dao.CityResourcesDao;
import cz.muni.fi.diplomka.datalayer.daoimpl.CityResourcesDaoImpl;
import cz.muni.fi.diplomka.datalayer.entity.CityResourcesEntity;
import cz.muni.fi.diplomka.servicelayer.dto.BuildingInCity;
import cz.muni.fi.diplomka.servicelayer.dto.CityResources;
import cz.muni.fi.diplomka.servicelayer.gamelogic.manager.CityBuildingManager;
import cz.muni.fi.diplomka.servicelayer.gamelogic.manager.CityResourcesManager;
import cz.muni.fi.diplomka.servicelayer.xmlconvertors.BuildingConvertor;
import cz.muni.fi.diplomka.servicelayer.xmlconvertors.LimitsConvertor;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.dozer.DozerBeanMapper;
import org.dozer.Mapper;

/**
 *
 * @author Jakub Kutil
 */
public class CityResourcesManagerImpl implements CityResourcesManager {

    private CityResourcesDao resourcesInCityDao = new CityResourcesDaoImpl();
    private Mapper mapper = new DozerBeanMapper();

    @Override
    public void lowerResource(Long cityId, ResourceType resourceType, int count) {
        if (cityId == null) {
            throw new IllegalArgumentException("CityId can not be null.");
        }
        if (resourceType == null) {
            throw new IllegalArgumentException("ResourceType can not be null.");
        }

        if (count < 0) {
            throw new IllegalArgumentException("Count can not be lower than zero.");
        }
        CityResources cityResources = new CityResources();
        cityResources.setCityId(cityId);
        cityResources.setResource(resourceType);
        cityResources.setResourceCount(this.getResourceCount(cityId, resourceType) - count);

        resourcesInCityDao.editResourcesInCity(mapper.map(cityResources, CityResourcesEntity.class));
    }

    @Override
    public void increaseResource(Long cityId, ResourceType resourceType, int count) {
        if (cityId == null) {
            throw new IllegalArgumentException("CityId can not be null.");
        }
        if (resourceType == null) {
            throw new IllegalArgumentException("ResourceType can not be null.");
        }

        if (count < 0) {
            throw new IllegalArgumentException("Count can not be lower than zero.");
        }
        CityResources cityResources = new CityResources();
        cityResources.setCityId(cityId);
        cityResources.setResource(resourceType);
        cityResources.setResourceCount(Math.min(this.getMaximumPossibleResourceCount(cityId, resourceType), this.getResourceCount(cityId, resourceType) + count));

        resourcesInCityDao.editResourcesInCity(mapper.map(cityResources, CityResourcesEntity.class));
    }

    @Override
    public int getResourceCount(Long cityId, ResourceType resourceType) {
        if (cityId == null) {
            throw new IllegalArgumentException("CityId can not be null.");
        }
        if (resourceType == null) {
            throw new IllegalArgumentException("ResourceType can not be null.");
        }

        return resourcesInCityDao.getAllSpecificResourcesCountInCityOfPlayer(cityId, resourceType);
    }

    @Override
    public int getMaximumPossibleResourceCount(Long cityId, ResourceType resourceType) {
        if (cityId == null) {
            throw new IllegalArgumentException("CityID cant be null");
        }

        if (resourceType == null) {
            throw new IllegalArgumentException("ResourceType cant be null");
        }

        int count = 1000;
        BuildingConvertor buildingConvertor = new BuildingConvertor();
        CityBuildingManager cityBuildingManager = new CityBuildingManagerImpl();

        List<BuildingInCity> buildingList = new ArrayList<>();
        switch (resourceType) {
            case Food:
                for (BuildingInCity building : cityBuildingManager.getAllBuildingsInCityOfType(cityId, BuildingType.Granary)) {
                    BuildingInCity b = buildingConvertor.getBuildingFromXML(building.getName().toString());
                    b.setLevel(building.getLevel());
                    buildingList.add(b);
                }
                break;
            case Gold:
                for (BuildingInCity building : cityBuildingManager.getAllBuildingsInCityOfType(cityId, BuildingType.Treasury)) {
                    BuildingInCity b = buildingConvertor.getBuildingFromXML(building.getName().toString());
                    b.setLevel(building.getLevel());
                    buildingList.add(b);
                }
                break;
            case Stone:
                for (BuildingInCity building : cityBuildingManager.getAllBuildingsInCityOfType(cityId, BuildingType.StoneDeposit)) {
                    BuildingInCity b = buildingConvertor.getBuildingFromXML(building.getName().toString());
                    b.setLevel(building.getLevel());
                    buildingList.add(b);
                }
                break;
            default:
                for (BuildingInCity building : cityBuildingManager.getAllBuildingsInCityOfType(cityId, BuildingType.Barracks)) {
                    BuildingInCity b = buildingConvertor.getBuildingFromXML(building.getName().toString());
                    b.setLevel(building.getLevel());
                    buildingList.add(b);
                    return b.getLevel() * 100;
                }
                break;
        }

        for (BuildingInCity b : buildingList) {
            count += b.getLevels().get(b.getLevel()).getProduces().get(resourceType);
        }

        return count;
    }

    @Override
    public int getResourceProductionCount(Long cityId, ResourceType resourceType) {
        if (cityId == null) {
            throw new IllegalArgumentException("CityID cant be null");
        }

        if (resourceType == null) {
            throw new IllegalArgumentException("ResourceType cant be null");
        }

        int count = 0;
        BuildingConvertor buildingConvertor = new BuildingConvertor();
        CityBuildingManager cityBuildingManager = new CityBuildingManagerImpl();

        List<BuildingInCity> buildingList = new ArrayList<>();
        switch (resourceType) {
            case Food:
                for (BuildingInCity building : cityBuildingManager.getAllBuildingsInCityOfType(cityId, BuildingType.Farm)) {
                    BuildingInCity b = buildingConvertor.getBuildingFromXML(building.getName().toString());
                    b.setLevel(building.getLevel());
                    buildingList.add(b);
                }
                for (BuildingInCity building : cityBuildingManager.getAllBuildingsInCityOfType(cityId, BuildingType.Castle)) {
                    BuildingInCity b = buildingConvertor.getBuildingFromXML(building.getName().toString());
                    b.setLevel(building.getLevel());
                    buildingList.add(b);
                }
                break;
            case Gold:
                for (BuildingInCity building : cityBuildingManager.getAllBuildingsInCityOfType(cityId, BuildingType.Mint)) {
                    BuildingInCity b = buildingConvertor.getBuildingFromXML(building.getName().toString());
                    b.setLevel(building.getLevel());
                    buildingList.add(b);
                }
                for (BuildingInCity building : cityBuildingManager.getAllBuildingsInCityOfType(cityId, BuildingType.Castle)) {
                    BuildingInCity b = buildingConvertor.getBuildingFromXML(building.getName().toString());
                    b.setLevel(building.getLevel());
                    buildingList.add(b);
                }
                break;
            case Stone:
                for (BuildingInCity building : cityBuildingManager.getAllBuildingsInCityOfType(cityId, BuildingType.Stonemason)) {
                    BuildingInCity b = buildingConvertor.getBuildingFromXML(building.getName().toString());
                    b.setLevel(building.getLevel());
                    buildingList.add(b);
                }
                for (BuildingInCity building : cityBuildingManager.getAllBuildingsInCityOfType(cityId, BuildingType.Castle)) {
                    BuildingInCity b = buildingConvertor.getBuildingFromXML(building.getName().toString());
                    b.setLevel(building.getLevel());
                    buildingList.add(b);
                }
                break;

            case Axe:
            case Pike:
            case Halberd:
            case Sword:
                for (BuildingInCity building : cityBuildingManager.getAllBuildingsInCityOfType(cityId, BuildingType.Blacksmith)) {
                    BuildingInCity b = buildingConvertor.getBuildingFromXML(building.getName().toString());
                    b.setLevel(building.getLevel());
                    buildingList.add(b);
                }
                break;

            case Bow:
            case Crossbow:
                for (BuildingInCity building : cityBuildingManager.getAllBuildingsInCityOfType(cityId, BuildingType.Fletcher)) {
                    BuildingInCity b = buildingConvertor.getBuildingFromXML(building.getName().toString());
                    b.setLevel(building.getLevel());
                    buildingList.add(b);
                }
                break;

            case Leather:
            case Chain:
            case Plate:
                for (BuildingInCity building : cityBuildingManager.getAllBuildingsInCityOfType(cityId, BuildingType.Armorer)) {
                    BuildingInCity b = buildingConvertor.getBuildingFromXML(building.getName().toString());
                    b.setLevel(building.getLevel());
                    buildingList.add(b);
                }
                break;

            case Horse:
                for (BuildingInCity building : cityBuildingManager.getAllBuildingsInCityOfType(cityId, BuildingType.Stable)) {
                    BuildingInCity b = buildingConvertor.getBuildingFromXML(building.getName().toString());
                    b.setLevel(building.getLevel());
                    buildingList.add(b);
                }
                break;
        }

        for (BuildingInCity b : buildingList) {
            if (b.getLevels().get(b.getLevel()).getProduces().get(resourceType) != null){
            count += b.getLevels().get(b.getLevel()).getProduces().get(resourceType);
            }
        }

        return count;
    }

    @Override
    public void createStartingResourcesForCity(Long cityId) {
        LimitsConvertor limitsConvertor = new LimitsConvertor();

        if (cityId == null) {
            throw new IllegalArgumentException("CityId cant be null");
        }
        Map<String, Integer> limits = limitsConvertor.getStartingResourcesFromXML();

        for (ResourceType resource : ResourceType.values()) {
            CityResources cityResources = new CityResources();
            cityResources.setCityId(cityId);
            cityResources.setResource(resource);

            cityResources.setResourceCount(limits.get(resource.toString()));
            resourcesInCityDao.addResourcesInCity(mapper.map(cityResources, CityResourcesEntity.class));
        }
    }
}
